package com.nowcoder.community.config;

import com.nowcoder.community.util.CommunityConstant;
import com.nowcoder.community.util.CommunityUtil;
import com.nowcoder.community.util.ResponseCode;
import com.nowcoder.community.util.auth.AuthPath;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;

import java.io.IOException;
import java.io.PrintWriter;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
public class SecurityConfig implements CommunityConstant, ResponseCode {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
                        // .requestMatchers(AuthPath.securityUncheckPaths).permitAll()
                        .requestMatchers(AuthPath.securityCheckPaths).hasAnyAuthority(
                                AUTHORITY_ADMIN,
                                AUTHORITY_USER,
                                AUTHORITY_MODERATOR
                        )
                        .requestMatchers("/data/**").hasAnyAuthority(
                                AUTHORITY_ADMIN
                        )
                        .requestMatchers(AuthPath.securityDiscussPostCheckPaths).hasAnyAuthority(
                                AUTHORITY_MODERATOR
                        )
                        // 删除帖子只有管理员可以删除
                        .requestMatchers("/discuss/delete").hasAnyAuthority(
                                AUTHORITY_ADMIN
                        )
                        .anyRequest().permitAll()
                );


        http
                .exceptionHandling((exceptionHandling) -> exceptionHandling
                        .authenticationEntryPoint(new AuthenticationEntryPoint() {
                            // 没有登陆的处理
                            @Override
                            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                                // 判断是不是异步请求
                                String xRequestedWith = request.getHeader("x-requested-with");
                                // 异步请求
                                if("XMLHttpRequest".equals(xRequestedWith)) {
                                    // 返回一个JSON对象
                                    response.setContentType("application/plain;charset=utf-8");
                                    PrintWriter writer = response.getWriter();
                                    writer.write(CommunityUtil.getJsonString(NOT_LOGIN_ACCESS, "您还没有登录"));
                                }
                                // 同步请求
                                else {
                                    // 重定向到登录页面
                                    response.sendRedirect(request.getContextPath() + "/login");
                                }
                            }
                        })
                        .accessDeniedHandler(new AccessDeniedHandler() {
                            // 权限不够的处理
                            @Override
                            public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                                String xRequestedWith = request.getHeader("x-requested-with");
                                // 异步请求
                                if("XMLHttpRequest".equals(xRequestedWith)) {
                                    // 返回一个JSON对象
                                    response.setContentType("application/plain;charset=utf-8");
                                    PrintWriter writer = response.getWriter();
                                    writer.write(CommunityUtil.getJsonString(NOT_AUTHENTICATED_ACCESS, "您没有访问此功能的权限"));
                                }
                                // 同步请求
                                else {
                                    // 重定向到登录页面
                                    response.sendRedirect(request.getContextPath() + "/denied");
                                }
                            }
                        })
                );

        http
                .httpBasic(withDefaults());

        // Spring Security会默认拦截/logout的请求
        // 我们绕过并执行自定义的logout逻辑 -> /securitylogout
        http.logout((logout) -> logout
                .logoutUrl("/security-logout")
        );



        return http.build();
    }

    @Bean
    public SecurityContextRepository securityContextRepository() {
        return new HttpSessionSecurityContextRepository();
    }

}
